using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using OpenComposite.EII;
using OpenComposite.EII.Repository;

namespace OpenComposite.SOBADesigner
{
	[ToolboxBitmap(typeof(UserControl))]
	internal partial class UCComponentTrees : UserControl, OpenComposite.EII.IRepositoryExplorerView
	{
		#region Initialization

		public UCComponentTrees(IServiceProvider serviceProvider)
		{
			_serviceProvider = serviceProvider;

			InitializeComponent();

			init();
		}

		private void init()
		{
			this.SetStyle(ControlStyles.ResizeRedraw, false);
			this.UpdateStyles();
		}

		#endregion

		#region Public Members

		#region Events

		public event EventHandler<ItemSelectedEventArgs> ItemSelected = null;
		public event EventHandler<ItemSelectedEventArgs> DeleteItem = null;

		public event EventHandler<ItemSelectedEventArgs> CreateProcessForMethod = null;

		public event EventHandler<ItemSelectedEventArgs> AddDiagram = null;
		public event EventHandler<ItemSelectedEventArgs> OpenDiagram = null;

		#endregion

		#region Methods
		public void UpdateTrees()
		{
			loadRepositories();
			//fillTreeViews();
		}
		public void UpdateTreeNode(TreeNode tn)
		{
			RepositoryItemBase item = tn.Tag as RepositoryItemBase;
			if ( item != null )
				tn.Text = item.Display;
		}
		public void UpdateRepository(int id)
		{
			foreach ( TabPage tp in tabCtrlTrees.TabPages ) {
				RepositoryObject rep = tp.Tag as RepositoryObject;
				if ( rep != null && rep.ID == id ) {
					rep.Reload();
					tp.Text = rep.Name;
					break;
				}
			}
		}
		public void UpdateCurrentRepository()
		{
			if ( tabCtrlTrees.InvokeRequired )
				return;

			TabPage tp = tabCtrlTrees.SelectedTab;
			if ( tp == null )
				return;

			//UCRepositoryTree reptree = null;
			//foreach ( Control ctrl in tp.Controls ) {
			//    if ( ctrl is UCRepositoryTree ) {
			//        reptree = (UCRepositoryTree)ctrl;
			//        break;
			//    }
			//}
			//if ( reptree == null )
			//    return;

			//reptree.UpdateRepository();
		}

		protected override object GetService(Type service)
		{
			if ( _serviceProvider != null )
				return _serviceProvider.GetService(service);
			else
				return base.GetService(service);
		}
		#endregion

		#region Properties

		[DefaultValue(TreeType.DomainEditor)]
		public TreeType Type
		{
			get { return _type; }
			set
			{
				_type = value;
				if ( !this.DesignMode )
					loadRepositories();
			}
		}

		public RepositoryService Repository
		{
			get { return (RepositoryService)GetService(typeof(RepositoryService)); }
		}
		#endregion Properties

		#endregion

		#region Private Members

		#region Variables

		private TreeType _type = TreeType.DomainEditor;
		//private Dictionary<ItemType, TreeNode> _dicFolders;
		private IServiceProvider _serviceProvider;

		#endregion

		#region Constant Fields

		#region Domain Table
		private const string _DOMAIN_ID = "domain_id";
		private const string _DOMAIN_NM = "domain_nm";
		private const string _DOMAIN_TYPE = "domain_type";
		private const string _DOMAIN_DESC = "domain_desc";
		private const string _DOMAIN_NTEXT = "domain_ntext";
		private const string _DOMAIN_SCHEMA = "domain_schema";
		private const string _DOMAIN_PARENT_ID = "parent_domain_id";
		#endregion
		#region System Table
		private const string _SYSTEM_ID = "system_id";
		private const string _SYSTEM_NM = "system_nm";
		private const string _SYSTEM_TYPE = "system_type";
		#endregion
		#region Nouns Table
		private const string _DOMVOCAB_ID = "domvocab_id";
		private const string _DOMVOCAB_NM = "domvocab_nm";
		private const string _DOMVOCAB_DESC = "domvocab_desc";
		private const string _DOMVOCAB_TYPE = "domvocab_type";
		private const string _DOMVOCAB_DATATYPE = "domvocab_datatype";
		private const string _DOMVOCAB_PARENT_ID = "parent_domvocab_id";
		#endregion
		#region Verbs Table
		private const string _VERBS_ID = "verb_id";
		private const string _VERBS_NM = "verb_nm";
		#endregion
		#region Service Table
		private const string _SERVICE_ID = "service_id";
		private const string _SERVICE_NM = "service_nm";
		private const string _SERVICE_TYPE = "service_type";
		private const string _SERVICE_DESC = "service_desc";
		private const string _SERVICE_NTEXT = "service_ntext";
		private const string _SERVICE_PARENT_ID = "parent_service_id";
		#endregion
		#region Service Method Table
		private const string _SVCMETHOD_ID = "svcmethod_id";
		private const string _SVCMETHOD_NM = "svcmethod_nm";
		private const string _SVCMETHOD_DESC = "svcmethod_desc";
		private const string _SVCMETHOD_INPUTXSD = "svcmethod_input_schema";
		private const string _SVCMETHOD_OUTPUTXSD = "svcmethod_output_schema";
		#endregion
		#region Domain Business Objects Table
		private const string _BOBJECT_ID = "bobj_id";
		private const string _BOBJECT_NM = "bobj_nm";
		private const string _BOBJECT_DESC = "bobj_desc";
		private const string _BOBJECT_PARENT_ID = "parent_bobj_id";
		#endregion Domain Business Objects Table

		#region Types

		private const int _TYPE_DOMAIN = 0;
		private const int _TYPE_CATEGORY = 1;

		#endregion

		#region Tree View Image Keys
		private const string _KEY_FOLDER_CLOSED = "folder_closed";
		private const string _KEY_FOLDER_OPEN = "folder_open";
		private const string _KEY_DOMAIN = "group";
		private const string _KEY_COMPUTER = "computer";
		private const string _KEY_FIELD = "field";
		private const string _KEY_SERVICE = "service";
		private const string _KEY_CLASS = "class";
		private const string _KEY_METHOD = "method";
		private const string _KEY_BRULE = "brule";
		private const string _KEY_BOBJECT = "bobject";
		private const string _KEY_MODULE = "module";
		private const string _KEY_VERB = "method";
		#endregion

		private const string _DOMAINNOUNS = "Domain Nouns";
		private const string _DOMAINVERBS = "Domain Verbs";
		private const string _DOMAINSERVICES = "Domain Services";
		private const string _DOMAINBRULES = "Domain Business Rules";
		private const string _DOMAINBOBJECTS = "Domain Business Objects";

		private const string _GENERICNOUNS = "Generic Nouns";
		private const string _GENERICVERBS = "Generic Verbs";
		private const string _GENERICSERVICES = "Generic Services";
		private const string _GENERICBRULES = "Generic Business Rules";
		private const string _GENERICBOBJECTS = "Generic Business Objects";

		private const string _SERVICESUBSERVICES = "Services";
		private const string _SERVICEOPERATIONS = "Operations";


		#endregion

		#region Methods

		private void loadRepositories()
		{
			tabCtrlTrees.TabPages.Clear();
			DataTable repos = Global.Data.SelectRepositoryTable(ItemType.Repository);
			if ( repos.Rows.Count == 0 ) {
				createNewRepositoryTab();
			} else {
				foreach ( DataRow row in repos.Rows ) {
					addRepositoryTab((int)row["repository_id"]);
				}
				onItemSelected(ItemType.Repository, null);
			}
		}
		private TabPage addRepositoryTab(int repositoryId)
		{
			// load repository
			RepositoryObject rep = this.Repository.GetItem<RepositoryObject>(repositoryId);

			// create new tab page
			TabPage tp = new TabPage(rep.Display);
			tp.Name = "Rep" + rep.ID.ToString();
			tp.Tag = rep;
			tabCtrlTrees.TabPages.Add(tp);

			UCComponentTree rt = new UCComponentTree(_serviceProvider);
			rt.CurrentTreeType = this.Type;
			rt.CurrentRepositoryID = rep.ID;
			rt.Dock = DockStyle.Fill;
			rt.ItemSelected += new EventHandler<ItemSelectedEventArgs>(rt_ItemSelected);
			rt.DeleteItem += new EventHandler<ItemSelectedEventArgs>(rt_DeleteItem);
			rt.CreateProcessForMethod += new EventHandler<ItemSelectedEventArgs>(rt_CreateProcessForMethod);
			rt.AddDiagram += new EventHandler<ItemSelectedEventArgs>(rt_AddDiagram);
			rt.OpenDiagram += new EventHandler<ItemSelectedEventArgs>(rt_OpenDiagram);
			tp.Controls.Add(rt);

			return tp;
		}

		void rt_OpenDiagram(object sender, ItemSelectedEventArgs e)
		{
			EventHandler<ItemSelectedEventArgs> tmp = this.OpenDiagram;
			if ( tmp != null )
				tmp(sender, e);
		}

		void rt_AddDiagram(object sender, ItemSelectedEventArgs e)
		{
			EventHandler<ItemSelectedEventArgs> tmp = this.AddDiagram;
			if ( tmp != null )
				tmp(sender, e);
		}

		void rt_CreateProcessForMethod(object sender, ItemSelectedEventArgs e)
		{
			EventHandler<ItemSelectedEventArgs> tmp = this.CreateProcessForMethod;
			if ( tmp != null )
				tmp(sender, e);
		}

		void rt_DeleteItem(object sender, ItemSelectedEventArgs e)
		{
			EventHandler<ItemSelectedEventArgs> tmp = this.DeleteItem;
			if ( tmp != null )
				tmp(sender, e);
		}

		void rt_ItemSelected(object sender, ItemSelectedEventArgs e)
		{
			EventHandler<ItemSelectedEventArgs> tmp = this.ItemSelected;
			if ( tmp != null )
				tmp(sender, e);
		}

		private void updateRepositoryTab(int repositoryId)
		{
			RepositoryObject rep = this.Repository.GetItem<RepositoryObject>(repositoryId);

			TabPage tp = tabCtrlTrees.TabPages["Rep" + rep.ID.ToString()];
			if ( tp == null )
				addRepositoryTab(repositoryId);
			else {
				TreeView tv = tp.Controls["Tree" + rep.ID.ToString()] as TreeView;
				if ( tv != null ) {
					tv.BeginUpdate();
					tv.Nodes.Clear();
					fillTree(tv, rep.ID);
					tv.EndUpdate();
				}
			}
		}
		private void createNewRepositoryTab()
		{
			bool bSaveContinue;
			do {
				this.Refresh();
				RepositoryObject rep =
					this.Repository.GetItem(ItemType.Repository, true, 0, true, out bSaveContinue) as RepositoryObject;
				if ( rep != null ) {
					TabPage tp = addRepositoryTab(rep.ID);
					tabCtrlTrees.SelectedTab = tp;
					onItemSelected(ItemType.Repository, null);
				}
			} while ( bSaveContinue );
		}
		private void deleteRepositoryTab(TabPage tabPage)
		{
			RepositoryItemBase item = tabPage.Tag as RepositoryItemBase;
			if ( item != null )
				if ( !item.Delete(true) )
					return;
			tabCtrlTrees.TabPages.Remove(tabPage);
		}

		private void fillTree(TreeView treeview, int repositoryId)
		{
			DataTable dt = Global.Data.GetRepositoryHierarchy(repositoryId);
			DataRow[] rows = dt.Select("parent_reptype_id IS NULL AND parent_id IS NULL");
			foreach ( DataRow row in rows ) {
				treeview.Nodes.Add(fillTreeRecursive(dt, row));
			}
		}
		private TreeNode fillTreeRecursive(DataTable dtRepository, DataRow currentRow)
		{
			// create new tree node
			TreeNode tn = new TreeNode();
			IRepositoryItem item =
				this.Repository.GetItem((ItemType)currentRow["child_reptype_id"],
													(int)currentRow["child_id"],
													currentRow["child_display"].ToString(),
													false);
			tn.Tag = item;
			// set text
			tn.Text = item.Display;

			// set image keys
			tn.ImageKey = item.ImageKey;
			tn.SelectedImageKey = item.SelectedImageKey;

			// add child tree nodes
			DataRow[] rows = dtRepository.Select(string.Format(
				"parent_reptype_id = {0} AND parent_id = {1}", (int)item.RepositoryItemType, item.ID));
			foreach ( DataRow row in rows ) {
				tn.Nodes.Add(fillTreeRecursive(dtRepository, row));
			}
			return tn;
		}

		private void onItemSelected(ItemType type, TreeNode node)
		{
			// set current repository id
			int id = getCurrentRepositoryId();
			// invoke ItemSeletected event
			EventHandler<ItemSelectedEventArgs> tmp = this.ItemSelected;
			if ( tmp != null ) {
				Global.Status.CurrentRepositoryId = id;
				if ( id > 0 )
					tmp(this, new ItemSelectedEventArgs(type, node, id));
			}
		}
		private void onDeleteItem(ItemType type, TreeNode node)
		{
			EventHandler<ItemSelectedEventArgs> tmp = this.DeleteItem;
			if ( tmp != null )
				tmp(this, new ItemSelectedEventArgs(type, node, getCurrentRepositoryId()));
		}
		//private void onCreateProcessForMethod(ItemType type, TreeNode node)
		//{
		//    EventHandler<ItemSelectedEventArgs> tmp = this.CreateProcessForMethod;
		//    if ( tmp != null )
		//        tmp(this, new ItemSelectedEventArgs(type, node, getCurrentRepositoryId()));
		//}

		//private TreeView getCurrentTreeView()
		//{
		//    TabPage tp = tabCtrlTrees.SelectedTab;
		//    TreeView tv = null;
		//    foreach ( Control ctrl in tp.Controls ) {
		//        if ( ctrl is TreeView ) {
		//            tv = (TreeView)ctrl;
		//            break;
		//        }
		//    }
		//    if ( tv == null )
		//        throw new NullReferenceException("No tree view at selected tab page.");

		//    return tv;
		//}
		private int getCurrentRepositoryId()
		{
			TabPage tp = tabCtrlTrees.SelectedTab;
			if ( tp == null )
				return -1;
			if ( !( tp.Tag is RepositoryObject ) )
				throw new Exception("TabPage has invalid tag (no Repository).");
			return ( (RepositoryObject)tp.Tag ).ID;
		}

		#endregion

		#region Event Handlers

		private void ucTrees_Load(object sender, EventArgs e)
		{
			if ( !this.DesignMode )
				loadRepositories();
		}

		private void tabCtrlTrees_MouseDown(object sender, MouseEventArgs e)
		{
			if ( e.Button == MouseButtons.Right ) {
				miRepDelete.Enabled = true;
				contextRepositories.Show(tabCtrlTrees, e.Location);
			}
		}
		private void UCTrees_MouseDown(object sender, MouseEventArgs e)
		{
			if ( e.Button == MouseButtons.Right ) {
				miRepDelete.Enabled = false;
				contextRepositories.Show(this, e.Location);
			}
		}

		private void tabCtrlTrees_SelectedIndexChanged(object sender, EventArgs e)
		{
			onItemSelected(ItemType.Repository, null);
		}

		#region Context Menu: contextRepositories

		private void miRepAdd_Click(object sender, EventArgs e)
		{
			createNewRepositoryTab();
		}
		private void miRepDelete_Click(object sender, EventArgs e)
		{
			deleteRepositoryTab(tabCtrlTrees.SelectedTab);
		}
		#endregion

		#endregion

		#endregion


		#region IRepositoryExplorerView Members


		public void SelectRepositoryItem(IRepositoryItem item)
		{
			this.SelectRepositoryItem(item, true);
		}
		public void SelectRepositoryItem(IRepositoryItem item, bool activate)
		{
			UCComponentTree tree = CurrentRepositoryTree as UCComponentTree;

			if ( tree != null ) {
				if ( tree.SelectRepositoryItem(item, activate) && activate ) {
					this.FindForm().Activate();
				}
			}
		}

		#endregion

		#region IRepositoryExplorerView Members


		public IRepositoryExplorerTree CurrentRepositoryTree
		{
			get
			{
				foreach ( Control ctrl in this.Controls[0].Controls ) {
					RepositoryObject rep = ctrl.Tag as RepositoryObject;
					if ( rep != null ) {
						if ( Global.Status.CurrentRepositoryId == rep.ID ) {
							return ctrl.Controls[0] as IRepositoryExplorerTree;
						}
					}
				}
				return null;
			}
		}

		#endregion
	}
}
